﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Shapes;
using System.Windows.Media;
using Bling.DSL;
using Bling.WPF;
using Bling.Geom;
using Bling.Util;
using Bling.Shapes;
using Bling.Physics;


namespace Bling.PhysicsTutorial {
  /// <summary>
  /// Simplest physics example. Use physics to create a goo cursor. 
  /// </summary>
  public class TrailCursor : PhysicsCanvas {
    public TrailCursor() : base("TrailCursor", 10) { }
    protected override Action Init(CanvasBl MainCanvas, World World) {
      MainCanvas.Background = Brushes.White;
      PathShapeBl Trail = new PathShapeBl(MainCanvas) {
        Stroke = { Brush = Brushes.Black, Thickness = 10 },
        IsHitTestVisible = false, 
      };
      LabelSliderBl Grain = new LabelSliderBl(MainCanvas) {
        Slider = { Minimum = 1, Maximum = 50d, Value = 10 }, 
        LabelName = "Grain", 
      };
     
      PlainBlock<Thumb, ThumbBl> block = new PlainBlock<Thumb, ThumbBl>(World, 200, i => {
        return new ThumbBl(MainCanvas) {
          Size = new Point(10, 10), Opacity = 0.2,
          CanDrag = false, Background = i.SelectColor(), ZIndex = Trail.ZIndex + 1, Visibility = false,
          CenterPosition = new PointBl(100,100) * i, IsHitTestVisible = false, 
        };
      }) { Name = "Trail", };
      Trail.Start = block[0].At;
      for (int i = 1; i < block.Count; i++) {
        Trail.Segments.Add(new LineSegmentBl() { Point = block[i].At });

      }
      PhysicsProperty<Point> PositionProperty = block.NewBodyProperty<Point>("Position");
      Func<PlainBlock<Thumb, ThumbBl>.Body, PointBl> Position = (body) => body.GetProperty(PositionProperty);
      PhysicsProperty<bool> DoUpdateProperty = block.NewBlockProperty<bool>("DoUpdate");
      BoolBl DoUpdate = block.GetProperty(DoUpdateProperty);

      PointBl r = new Random();
      block.ForAll(body => {

        var diff = Position(body) - Position(body.Prev[1]);

        Position(body).Relax[1, body.Index > 0 & DoUpdate] = Position(body.Prev[1]);
        Position(body).Link.To = body.At.CenterPosition;
      });
      return () => {
        Action UpdateMouse = PointBl.Assign(Position(block[0]), MainCanvas.MousePosition);
        Action SetDoUpdate = BoolBl.Assign(DoUpdate, ((Position(block[0]) - MainCanvas.MousePosition).Length >= Grain));
        Func<bool> DoUpdateF = DoUpdate.AsFunc;
        MainCanvas.OnMouseMove = (x, y) => {
          SetDoUpdate();
          if (DoUpdateF())
            UpdateMouse();
          return true;
        };
      };
    }
  }
}
